<?php


namespace app\tcpserver\controller;

use think\cache\driver\Redis;
use think\worker\Server;
use Workerman\Lib\Timer;
use Workerman\Connection\TcpConnection;


class TcpServer extends Server
{

    protected $socket = 'tcp://0.0.0.0:18599';
    protected $processes = 1;//四进程
    protected $uidConnections = [];

    public function predis()
    {
        return new Redis([
            'host'       => '127.0.0.1',
            'port'       => 6379,
            'password'   => 'xiaochun123',
            'select'     => 0,
            'timeout'    => 0,
            'expire'     => 0,
            'persistent' => false,
            'prefix'     => '',
            'serialize'  => true,
        ]);
    }


    public function onWorkerStart($worker)
    {
        $redis = $this->predis();
        Timer::add(0.5,function() use($redis,$worker){
            $len = $redis->llen('control_cmd');
            if(!empty($len)){
                $queue_cmd_str = $redis->rpop('control_cmd');
                if($queue_cmd_str){
                    $queue_cmd_arr = json_decode($queue_cmd_str,true);
                    $queue_cmd = $queue_cmd_arr['command']??0;
                    $queue_fp = $queue_cmd_arr['fd']??0;
                    $command_type = $queue_cmd_arr['commandType']??0;
                    $unit = $queue_cmd_arr['unit']??0;
                    $tao = $queue_cmd_arr['tao']??'';
                    $u_number = substr($tao,2,2);
                    if(empty($queue_cmd)){
                        echo PHP_EOL.'['.date('Y-m-d H:i:s').']----------发送命令Start---------------' . PHP_EOL;
                        if($command_type==1){
                            echo $u_number.'====1111111111111111111111'.PHP_EOL;
                            if($u_number>=21&&$u_number<=42){
                                //易能控制
                                echo $unit.'====2222222222'.PHP_EOL;
                                if(!empty($unit)){
                                    $unitStr = $this->bu(dechex($unit*100),4);
                                    $commandContent = '01061E01'.$unitStr;
                                    $crc16 = $this->crcEn($commandContent);
                                    $queue_cmd = $commandContent.$crc16;
//                                    01061E0103200FAD
//                                    01061E0006F94C
//                                    0141701502b2B7D4
//                                    01860183a0
                                }
                            } else{
                                if(!empty($unit)){
                                    $unitStr = $this->bu(dechex($unit*100),4);
                                    $commandContent = '01417015'.$unitStr;
                                    $crc16 = $this->crc16($commandContent);
                                    $queue_cmd = '01417015'.$unitStr.$crc16;
                                }
                            }
                            if(!empty($queue_cmd)){
                                echo $queue_cmd;
                                $cmd= hex2bin($queue_cmd);
                                $this->send_uid($queue_fp,$cmd);
                                echo PHP_EOL.'----------发送命令End---------------' . PHP_EOL;
                            }
                        }
                    }

                    if(!empty($queue_cmd) && $command_type!=1){
                        if($u_number>=21&&$u_number<=42){
                            if($command_type==2||$command_type==3){
                                if($command_type==2){
//                                zhuan
                                    $com = '05';
                                }

                                if($command_type==3){
//                                ting
                                    $com = '06';
                                }
                                if(isset($com)){
                                    $commandContent = '01061E0000'.$com;
                                    $crc16 = $this->crcEn($commandContent);
                                    $queue_cmd = $commandContent.$crc16;
                                    echo $queue_cmd;
                                    $cmd= hex2bin($queue_cmd);
                                    $this->send_uid($queue_fp,$cmd);
                                    echo PHP_EOL.'----------发送命令End---------------' . PHP_EOL;
                                }
                            }
//
                        }else{
                            echo PHP_EOL . '[' . date('Y-m-d H:i:s') . ']----------发送命令Start---------------' . PHP_EOL;
                            echo $queue_cmd;
                            $cmd = hex2bin($queue_cmd);
                            $this->send_uid($queue_fp, $cmd);
                            echo PHP_EOL . '----------发送命令End---------------' . PHP_EOL;
                        }

                    }
                }
            }
        });
    }

    public function onConnect($client_id)
    {
        //绑定数据
        echo $client_id->id.'连接'.PHP_EOL;
    }

    public function onMessage(TcpConnection $client_id,$message)
    {
        $uniName = substr($message,0,4);
        $this->uidConnections[$client_id->id] = $client_id;
//        echo $client_id->id.'唯一标识：'.$uniName.PHP_EOL;
        $this->predis()->set('fd_sn'.$uniName,$client_id->id,60);
        $this->predis()->set('fdGetUni'.$client_id->id,$uniName,60);
        $command = bin2hex(substr($message,4));
//        if($uniName=='J052'){
//            echo '################'.$message.PHP_EOL;
//        }
//        014170150058373b
//        014170150058373B11
//        echo '--------------------START------------------'.PHP_EOL;
//        echo $client_id->id.'接收命令详细_____'.date('Y-m-d H:i:s').'______'.$command.PHP_EOL;
        //关于频率下发的回调
        $name = '其它';
        $dataStr = '';
        if(!empty($command)){
            $address = substr($command,0,2);
            $tao = $uniName;//默认第一套
            $commandType = substr($command,2,2);
            //唯一标识绑定
            if($commandType=='41' || $commandType=='c1'){
                $this->predis()->lpush('command41'.$client_id->id,json_encode(['str'=>$command],JSON_UNESCAPED_UNICODE));
            }
            if($tao=='J025'){
                echo $client_id->id.'['.$uniName.']'.'接收命令'.$commandType.'详细_____'.date('Y-m-d H:i:s').'______'.$command.PHP_EOL;
            }
//            01880187c0
//            01860183a0
            if($commandType=='06' || $commandType=='88' || $commandType=='86'){
                $this->predis()->lpush('command41'.$client_id->id,json_encode(['str'=>$command],JSON_UNESCAPED_UNICODE));
            }
            $this->predis()->set('onLineStatus'.$tao.'_all',1,100);
//            J001
            switch ($address) {
                case '02':
                    $data = [];
                    $type = 1;
                    if($commandType=='03'){
                        $type = 1;
                        $name = '【天信气表】';
                        $this->predis()->set('onLineStatus'.$tao.'_'.$type,1,60);
                        $dataStr .= '指令：'.$command.PHP_EOL;
                        $dataStr .= $name.'气表在线状态：1'.PHP_EOL;
                        $dataStr .= '唯一标识：'.$uniName.PHP_EOL;
                        $dataStr .= '气表数据解析_____'.PHP_EOL;
                        $dataStr .= '标况总量高位：'.$this->formatterHex(substr($command,6,8)).PHP_EOL;
                        $dataStr .= '标况总量低位：'.$this->formatterHex(substr($command,14,8)).PHP_EOL;
                        $dataStr .= '标况流量：'.$this->formatterHex(substr($command,22,8)).PHP_EOL;
                        $dataStr .= '工况流量：'.$this->formatterHex(substr($command,30,8)).PHP_EOL;
                        $dataStr .= '温度：'.$this->formatterHex(substr($command,38,8)).'℃'.PHP_EOL;
                        $bpYl = $this->formatterHex(substr($command,46,8));
                        $dataStr .= $name.'压力：'.$bpYl.PHP_EOL;
                        $data = json_encode([
                            'type'=>1,
                            'uni_name'=>$uniName,
                            'blHigh'=>$this->formatterHex(substr($command,6,8)),
                            'blLow'=>$this->formatterHex(substr($command,14,8)),
                            'bkll'=>$this->formatterHex(substr($command,22,8)),
                            'gkll'=>$this->formatterHex(substr($command,30,8)),
                            'wd'=>$this->formatterHex(substr($command,38,8)),
                            'yl'=>$bpYl,
                            'times'=>date('Y-m-d H:i:s')
                        ],JSON_UNESCAPED_UNICODE);
                    }

                    if($commandType=='04'){
                        $type = 1;
                        $name = '延安亚泰、河南茂源气表';
//                        0204 104009E2 CB4789FC 1141A494 B83DC0D0 FD6BD8
//                        0203 18000000 00489b57 25411346 4e414870 0e421540 00429dc800bf7f
//                        0203 18000000 0048c315 484135b7 524118cb a241a400 0042f14c 006bb3
//                        0204 10 00000000 47e65433 42079c95 3dc2740f 874e
                        //      瞬时流量    总量      温度     压力
//                        瞬时流量  总量
                        $this->predis()->set('onLineStatus'.$tao.'_'.$type,1,60);
                        $dataStr .= '指令：'.$command.PHP_EOL;
                        $dataStr .= '气表在线状态：1'.PHP_EOL;
                        $dataStr .= '唯一标识：'.$uniName.PHP_EOL;
                        $dataStr .= '气表数据解析_____'.PHP_EOL;
                        $dataStr .= '标况总量高位：'.'0'.PHP_EOL;
                        $dataStr .= '标况总量低位：'.$this->formatterHex(substr($command,14,8)).PHP_EOL;
                        $dataStr .= '标况流量：'.$this->formatterHex(substr($command,6,8)).PHP_EOL;
                        $dataStr .= '工况流量：'.'0'.PHP_EOL;
                        $dataStr .= '温度：'.$this->formatterHex(substr($command,16,8)).'℃'.PHP_EOL;

//                        $bpYl = $this->fuDex(substr($command,30,8));
                        $bpYl = $this->formatterHex(substr($command,30,8));
                        $bpYl = round($bpYl*1000,3);
                        $dataStr .= '变频器压力：'.$bpYl.PHP_EOL;
                        $data = json_encode([
                            'type'=>1,
                            'uni_name'=>$uniName,
                            'blHigh'=>0,
                            'blLow'=>$this->formatterHex(substr($command,14,8)),
                            'bkll'=>$this->formatterHex(substr($command,6,8)),
                            'gkll'=>0,
                            'wd'=>$this->formatterHex(substr($command,22,8)),
                            'yl'=>$bpYl,
                            'times'=>date('Y-m-d H:i:s')
                        ],JSON_UNESCAPED_UNICODE);
                    }

                    $this->predis()->lpush('heartLogsOfDevice'.$tao,$data);
                    //设定实时数据
                    $this->predis()->set('immediately_message_'.$tao.'_'.$type,$data,50);

                    //气表
                    break;

                case '10':
                    $name = '井下压力计';
                    $type = 2;
                    $this->predis()->set('onLineStatus'.$tao.'_'.$type,1,60);
                    $dataStr .= '指令：'.$command.PHP_EOL;
                    $dataStr .= '井下压力计在线状态：1'.PHP_EOL;
                    $dataStr .= '唯一标识：'.$uniName.PHP_EOL;
                    $dataStr .= '井下压力计数据解析_____'.PHP_EOL;
//                  10 03 04 ffff 055a 787d
                    $pa = $this->fuDex(substr($command,6,4));
                    $xiaoshu = '02';
                    $unitArr = [
                        '00'=>1,
                        '01'=>10,
                        '02'=>100,
                        '03'=>1000,
                    ];
                    if($pa<0){
                        $pa = 0;
                    }
//                    03   03    02      00        05    01 87
                    //   通信  波特   单位mpa  小数点位   数值   CRC
                    $pa = round($pa/$unitArr[$xiaoshu]??1,3);
                    $tem = round(hexdec(substr($command,10,4))/100,2);
                    $dataStr .= '井下压力：'.$pa.'MPa'.PHP_EOL;
                    $dataStr .= '井下温度：'.$tem.'℃'.PHP_EOL;
                    $data = json_encode([
                        'type'=>2,
                        'uni_name'=>$uniName,
                        'yali'=>$pa,
                        'temp'=>$tem,
                        'times'=>date('Y-m-d H:i:s')
                    ],JSON_UNESCAPED_UNICODE);
                    $this->predis()->lpush('heartLogsOfDevice'.$tao,$data);
                    $this->predis()->set('immediately_message_'.$tao.'_'.$type,$data,50);
                    //气表
                    break;

                case '01':
                    if($commandType=='03'){
                        $name = '变频器';
                        $dataStr .= '指令：'.$command.PHP_EOL;
                        $dataStr .= '变频器在线状态：1'.PHP_EOL;
                        $dataStr .= '唯一标识：'.$uniName.PHP_EOL;
                        $dataStr .= '变频器数据解析_____'.PHP_EOL;
                        $type01 = strlen($command);
                        if($type01>14){
                            if($type01==30){
                                $pinLv = round(hexdec(substr($command,6,4))/100,3);
                                $scPinLv = round(hexdec(substr($command,10,4))/100,1);
                                $scVol = round(hexdec(substr($command,14,4))/10,1);
                                $scDianYa = round(hexdec(substr($command,18,4)),3);
                                $motherVoltage = round(hexdec(substr($command,22,4))/10,3);
//                                01030a02b302b3007b003716f13d79
                                $dataStr .= '易能EN600变频器解析：'.PHP_EOL;
                                $dataStr .= '设定频率：'.$pinLv.PHP_EOL;
                                $dataStr .= '输出频率：'.$scPinLv.PHP_EOL;
                                $dataStr .= '输出电流：'.$scVol.PHP_EOL;
                                $dataStr .= '输出电压：'.$scDianYa.PHP_EOL;
                                $dataStr .= '母线电压：'.$motherVoltage.PHP_EOL;
                                $type = 3;
                                $this->predis()->set('onLineStatus'.$tao.'_'.$type,1,120);
                                $data = json_encode([
                                    'type'=>3,
                                    'uni_name'=>$uniName,
                                    'pinlv'=>$scPinLv,
                                    'voltage'=>$scDianYa,
                                    'run_power'=>0,
                                    'current'=>$scVol,
                                    'run_speed'=>0,
                                    'mother_voltage'=>$motherVoltage,
                                    'run_len'=>0,
                                    'times'=>date('Y-m-d H:i:s')
                                ],JSON_UNESCAPED_UNICODE);
                            } else {
                                $pinLv = round(hexdec(substr($command,6,4))/100,3);
                                $voltage = round(hexdec(substr($command,10,4))/10,1);
                                $runPower = round(hexdec(substr($command,14,4))/100,3);
                                $runSpeed = round(hexdec(substr($command,18,4)),3);
                                $motherVoltage = round(hexdec(substr($command,22,4)),3);
                                $runLen = round(hexdec(substr($command,26,4))/10,3);
                                $dataStr .= 'E90变频器解析：'.PHP_EOL;
                                $dataStr .= '运行频率：'.$pinLv.PHP_EOL;
                                $dataStr .= '运行电压：'.$voltage.PHP_EOL;
                                $dataStr .= '运行功率：'.$runPower.PHP_EOL;
                                $dataStr .= '运行速度：'.$runSpeed.PHP_EOL;
                                $dataStr .= '母线电压：'.$motherVoltage.PHP_EOL;
                                $dataStr .= '运行转矩：'.$runLen.PHP_EOL;
                                $type = 3;
                                $this->predis()->set('onLineStatus'.$tao.'_'.$type,1,120);
                                $data = json_encode([
                                    'type'=>3,
                                    'uni_name'=>$uniName,
                                    'pinlv'=>$pinLv,
                                    'voltage'=>$voltage,
                                    'run_power'=>$runPower,
                                    'run_speed'=>$runSpeed,
                                    'mother_voltage'=>$motherVoltage,
                                    'run_len'=>$runLen,
                                    'times'=>date('Y-m-d H:i:s')
                                ],JSON_UNESCAPED_UNICODE);
                            }

                        } else {
//                        01 03 02 03 d5 792b
                            $current = round(hexdec(substr($command,6,4))/100,2);
                            $dataStr .= '电流：'.$current.'A'.PHP_EOL;
                            $type = 5;
                            $this->predis()->set('onLineStatus'.$tao.'_'.$type,1,120);
                            $data = json_encode([
                                'type'=>$type,
                                'uni_name'=>$uniName,
                                'current'=>$current,
                                'times'=>date('Y-m-d H:i:s')
                            ],JSON_UNESCAPED_UNICODE);
                        }
                        $this->predis()->lpush('heartLogsOfDevice'.$tao,$data);
                        $this->predis()->set('immediately_message_'.$tao.'_'.$type,$data,50);
                    }

                    break;

                case '03':
                    $name = '套压压力计';
                    $dataStr .= '指令：'.$command.PHP_EOL;
                    $dataStr .= '套压压力计在线状态：1'.PHP_EOL;
                    $dataStr .= '唯一标识：'.$uniName.PHP_EOL;
                    $type = 4;
                    $this->predis()->set('onLineStatus'.$tao.'_'.$type,1,60);
//                    03 03 02 0020 c05c
                    $dataStr .= '套压压力计数据解析_____'.PHP_EOL;

//                    $taoValue = round(hexdec(substr($command,6,4))/1000,3);
                    $taoValue = $this->fuDex(substr($command,6,4));
                    $qianArr = ['J001','J002','J004','J005','J007','J009','J015','J016','J017','J018','J019','J046','J021','J022','J025','J027','J030','J031','J032','J033','J036','J037','J038','J039','J040','J041','J042','J043','J044','J046','J047','J048','J049','J050','J051','J052','J053','J054'];
                    $xiaoshu = '02';
                    if(in_array($uniName,$qianArr)){
                        $xiaoshu = '03';
                    }
                    $unitArr = [
                        '00'=>1,
                        '01'=>10,
                        '02'=>100,
                        '03'=>1000,
                    ];
                    if($taoValue<0){
                        $taoValue = 0;
                    }
//                    03   03    02      00        05    01 87
                //   通信  波特   单位mpa  小数点位   数值   CRC
                    $dataStr .= '套压压力计数据解析除数_____'.$unitArr[$xiaoshu]??''.PHP_EOL;

                    $taoValue = round($taoValue/$unitArr[$xiaoshu]??1,3);
                    $dataStr .= '套压值：'.$taoValue.'MPa'.PHP_EOL;
                    $data = json_encode([
                        'type'=>4,
                        'uni_name'=>$uniName,
                        'tao_value'=>$taoValue,
                        'times'=>date('Y-m-d H:i:s')
                    ],JSON_UNESCAPED_UNICODE);
                    $this->predis()->set('immediately_message_'.$tao.'_'.$type,$data,50);
                    $this->predis()->lpush('heartLogsOfDevice'.$tao,$data);
                    break;
            }

            //展示链接开始
            $arr = $this->predis()->get('HisLog');
            if(!empty($arr)){
                $arr = json_decode($arr,true);
            } else {
                $arr = [];
            }
            array_push($arr,$tao.'=='.'【'.$name.'】'.'接收时间：'.date('Y-m-d H:i:s').'内容：'.$command.'原始指令：');

            $arr2 = $this->predis()->get('HisLog2');
            if(!empty($arr2)){
                $arr2 = json_decode($arr2,true);
            } else {
                $arr2 = [];
            }
            array_push($arr2,$tao.'=='.'【'.$name.'】'.'解析：'.date('Y-m-d H:i:s').'内容：'.$dataStr.'原始指令：');

            if(count($arr)>100){
                $arr = array_splice($arr,-100);
            }
            $this->predis()->set('HisLog',json_encode($arr,JSON_UNESCAPED_UNICODE));

            if(count($arr2)>100){
                $arr2 = array_splice($arr2,-100);
            }
            $this->predis()->set('HisLog2',json_encode($arr2,JSON_UNESCAPED_UNICODE));
            //展示链接结束
//            echo '即时更新结果开始-------------'.PHP_EOL;
//            for ($i=1;$i<=5;$i++){
//                echo $this->predis()->get('immediately_message_'.$tao.'_'.$i).PHP_EOL;
//            }
//            echo '即时更新结果结束-------------'.PHP_EOL;
        }
    }

    public function taoUni()
    {
        return ['J001','J002','J004','J005','J007','J009','J015','J016','J017','J018','J019'];
    }

    public function send_uid($uid,$message)
    {
        if(isset($this->uidConnections[$uid])){
            // 获取之前用户的链接
            $conn = $this->uidConnections[$uid];
            //echo $uid.PHP_EOL;
            $conn->send($message);
            return true;
        }
        return false;
    }

    public function onClose($client_id)
    {
        unset($this->uidConnections[$client_id->id]);
        echo $client_id->id.'断开'.PHP_EOL;
    }

    //有符号十六进制转换
    public function fuDex($hex)
    {
        $dec = hexdec($hex);
        if ($dec > 0x7FFF) {
            $signedInt = $dec - 0x10000;
        } else {
            $signedInt = $dec;
        }
        return $signedInt;
    }

    /**
     * 大小端切换
     * @param $attr
     * @return string
     */
    public function formaster16($str)
    {
        $res = str_split($str,2);
        $newArr = [];
        $key = 0;
        foreach ($res as $k=>$v){
            $key++;
            $newArr[$key] = $v;
        }
        return implode('', array_reverse($newArr));
    }

    public function crc16($str)
    {
        $dataBytes = [];
        for ($i = 0; $i < strlen($str); $i += 2) {
            $dataBytes[] = hexdec(substr($str, $i, 2));
        }
        $crc = $this->calculateCRC16Modbus($dataBytes);
        return $this->bu($this->formaster16(strtoupper(dechex($crc))));
    }


    public function calculateCRC16Modbus($data)
    {
        $crc = 0xFFFF;
        $polynomial = 0xA001;  // This is the polynomial x^16 + x^15 + x^2 + 1
        foreach ($data as $byte) {
            $crc ^= $byte;
            for ($i = 0; $i < 8; $i++) {
                if ($crc & 0x0001) {
                    $crc = (($crc >> 1) ^ $polynomial) & 0xFFFF;
                } else {
                    $crc >>= 1;
                }
            }
        }
        return $crc;
    }

    public function formatterHex($hexValue)
    {
        $res = str_split($hexValue,2);
        $newArr = [];
        $key = 0;
        foreach ($res as $k=>$v){
            $key++;
            $newArr[$key] = $v;
        }
        $hexValue = implode('', array_reverse($newArr));
        $decision = 2;
        $binaryData = hex2bin($hexValue);
        $floatValue = unpack("f", $binaryData);
        return sprintf('%.' . $decision . 'f', $floatValue[1]);
    }

    public function bu($str,$le=4)
    {
        $len = strlen($str);
        $new_str = '';
        if ($len < $le) {
            $a = $le - $len;
            for ($i = 1; $i <= $a; $i++) {
                $new_str .= '0';
            }
            return $new_str.$str;
        } else {
            return $str;
        }
    }


    public function crc16EN($string, $length = 0)
    {
        $auchCRCHi = array(
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
            0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
            0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
            0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
            0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
            0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
            0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
            0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
            0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
            0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
            0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
            0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
            0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
            0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
            0x40
        );
        $auchCRCLo = array(
            0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
            0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
            0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
            0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
            0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
            0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
            0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
            0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
            0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
            0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
            0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
            0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
            0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
            0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
            0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
            0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
            0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
            0x40
        );
        $length        = ($length <= 0 ? strlen($string) : $length);
        $uchCRCHi    = 0xFF;
        $uchCRCLo    = 0xFF;
        $uIndex      = 0;
        for ($i = 0; $i < $length; $i++) {
            $uIndex      = $uchCRCLo ^ ord(substr($string, $i, 1));
            $uchCRCLo    = $uchCRCHi ^ $auchCRCHi[$uIndex];
            $uchCRCHi    = $auchCRCLo[$uIndex];
        }
        return (chr($uchCRCLo) . chr($uchCRCHi));
    }



    public function crcEn($str='',$len=0)
    {
        $s = pack('H*',$str);
        $t = $this->crc16EN($s,$len);
        return strtoupper(unpack("H*",$t)[1]);
    }
}
